package xw.qxypt.modules.socket.util;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SocketUtil {
    private static final String UMB_SOH = "01";// 1个帧的开始的控制字符(01h) 1 byte
    private static final String UMB_VER = "10";// 头版本号 比如.: V 1.0 <ver> = 10h = 16d; 1
    private static final String UMB_FROM = "01F0";// 服务器地址 可默认 2 bytes
    private static final String UMB_STX = "02";// 引用数据开始控制字符(02h); 1 byte
    private static final String UMB_VERC = "10";// 命令的版本; 1 byte
    private static final String UMB_ETX = "03";// 数据段结束字节(03h); 1 byte
    private static final String UMB_EOT = "04";// 帧结束符(04h); 1 byte


    public static String sendData(String mbapADUMeter, OutputStream out) {
        String mes = null;
        byte[] buffer = new byte[mbapADUMeter.length() / 2];
        String contentHex = mbapADUMeter;
        for (int i = 0; i < contentHex.length(); i += 2) {
            try {
                buffer[i / 2] = (byte) (0xff & Integer.parseInt(contentHex.substring(i, i + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            out.write(buffer);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            mes = "sendFalse";
        }
        return mes;
    }

    /**
     * 依据设备类型和设备ID创建上位机请求帧（LUFFT）
     *
     * @param id
     *            设备ID 转换为16进制后不能超过3位
     * @param type
     *            设备类型 必须为1位16进制数
     * @return
     */
    public static String creatLUFFTSendPacage(String id, String type) {

        // 创建<to>,例如：
        // 路检器类型为 4 = 4h 设备 ID (按序编排)为 0001 = 001h
        // 类型和设备 ID 放一起为 4001h.
        // <to>=0104
        // type = "15";
        // id = "1";
        type = Integer.toHexString(Integer.parseInt(type));
        id = Integer.toHexString(Integer.parseInt(id));
        switch (id.length()) {
            case 1:
                id = "00" + id;
                break;
            case 2:
                id = "0" + id;
                break;
        }
        String umb_to = type + id;
//		System.out.println("to = " + umb_to);
        String[] toArray = new String[umb_to.length() / 2];
        for (int i = 0; i < toArray.length; i++) {
            toArray[i] = umb_to.substring(i * 2, i * 2 + 2);
        }
        umb_to = "";
        for (int i = toArray.length - 1; i >= 0; i--) {
            umb_to += toArray[i];
        }
        //System.out.println("UMB_TO = " + umb_to);
        // 通道号，16进制表示
        String umb_channel = "";
        // 命令类型，16进制表示：23-单通道，2F-多通道
        String umb_cmd = "";
        String umb_num = "";
        // 根据不同的设备类型组织不通指令
        switch (Integer.valueOf(Integer.parseInt(type, 16))) {
            case 10:// MARWIS/STARWIS遥感式路面传感器
                //6400 路面温度  6E00 空气温度 D200 相对湿度 7800 露点温度 C800 相对路面温度的相对湿度 5802 水膜高度 5902 光滑表面的水膜高度  8403 路面状况 2003 含冰量  3403   摩擦系数  BC02 冰点温度
                umb_channel = "64006E00D2007800C80058025902840320033403BC02";
                umb_cmd = "2F";
                umb_num = Integer.toHexString(umb_channel.length() / 4);
                if (umb_num.length() < 2) {
                    umb_num = "0" + umb_num;
                }

                break;
            case 9:// IRS31被动式路面探测器
                //6500 路面温度 6F00 路基温度（5cm） 7900 路基温度（30cm） 9700   冰点温度 NaCl AB00 冰点温度 MgCl BF00   冰点温度 CaCl 5902 水膜高度 2103   含盐量 NaCl
                //2A03  含冰比例 3403 摩擦系数 3F03   含盐量 MgCl 4903 含盐量 CaCl 8403 路面状况
                umb_channel = "65006F0079009700AB00BF00590221032A0334033F0349038403";
                umb_cmd = "2F";
                umb_num = Integer.toHexString(umb_channel.length() / 4);
                if (umb_num.length() < 2) {
                    umb_num = "0" + umb_num;
                }

                break;
            case 4:// ARS31主动式路面传感器
                //6500 铜探头温度  6F00 路面温度  9700 冰点温度  2103 含盐量 NaCl   2303 含盐量 CaCl   2503  含盐量 MgCl 8403 冰点温度测量状态  8503 实时结冰可能性
                umb_channel = "65006F00970021032303250384038503";
                umb_cmd = "2F";
                umb_num = Integer.toHexString(umb_channel.length() / 4);
                if (umb_num.length() < 2) {
                    umb_num = "0" + umb_num;
                }
                break;
            case 3:// VS20 能见度分析仪
                umb_channel = "5902";
                umb_cmd = "23";
                umb_num = Integer.toHexString(umb_channel.length() / 4);
                if (umb_num.length() < 2) {
                    umb_num = "0" + umb_num;
                }
                break;
            case 7:// WS600气象传感器
                //6400 温度 2C01 气压  9001 风速  F401 风向  6C02 降水量  C800  相对湿度 6F00 风寒温度  7200 湿球温度  D700 比焓 3403 降水强度 BC02 降水类型
                umb_channel = "64006E002C019001F4016C02C8006F007200D7003403BC02";
                umb_cmd = "2F";
                umb_num = Integer.toHexString(umb_channel.length() / 4);
                if (umb_num.length() < 2) {
                    umb_num = "0" + umb_num;
                }
                break;
        }
        String dataStr = "";

        if(umb_cmd.equals("23"))
            dataStr = umb_cmd + UMB_VERC  + umb_channel;
        else
            dataStr = umb_cmd + UMB_VERC + umb_num  + umb_channel;

        int len = dataStr.length() / 2;
        String umb_len = Integer.toHexString(len);
        if (umb_len.length() < 2)
            umb_len = "0" + umb_len;
        // 组织发送请求帧

        // 路检器类型为4 = 4h 设备ID (按序编排)为0001 = 001h
        // 类型和设备ID放一起为4001h；低字节在前4001h转为0140h

        String sendPack = UMB_SOH + UMB_VER + umb_to + UMB_FROM + umb_len
                + UMB_STX + dataStr + UMB_ETX;
        //System.out.println("1.被校验字段 从第1位SOH到ETX = " + sendPack);
        // 从SOH->ETX 进行CRD校验
        String crc = crc_16_CCITT(sendPack);
        //System.out.println("2.crc 校验码 = " + crc);
        // 在发送帧中校验码低字节在前，如D961->61D9.
        String[] crcArray = new String[crc.length() / 2];
        if (!crc.equals("0")) {
            for (int i = 0; i < crcArray.length; i++) {
                crcArray[i] = crc.substring(i * 2, i * 2 + 2);
            }
        }
        for (int i = crcArray.length - 1; i >= 0; i--) {
            sendPack = sendPack + crcArray[i];
        }
        sendPack = sendPack + UMB_EOT;
//		System.out.println("3.发送帧 = " + sendPack);
        return sendPack.toUpperCase();
    }


    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }


        return stringBuilder.toString();
    }

    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 监听到客户端tcp连接后，收到心跳包，解析出设备ID。 并依据ID获取传感器信息List，用于组织请求指令。
     *
     */
    public static void doSomething(String ret) {
        Date now = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "yyyy/MM/dd HH:mm:ss");
        System.out.println(dateFormat.format(now) + "--" + ret);
    }

    /**
     * 将byte[]转化十六进制的字符串
     *
     * @param b
     * @return 十六进制的字符串
     */
    public static String toHexString(byte[] b) {
        String ret = "";
        String hex = "";
        for (int i = 0; i < b.length; i++) {
            hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }

    public static String crc_16_CCITT(String str) {
        int crc = 0xFFFF; // initial value
        if (str == null || str.trim().equals("")) {
            return "0";
        }
        for (int index = 0; index < str.length() / 2; index++) {
            String subStr = str.substring(index * 2, index * 2 + 2);
            int input = Integer.parseInt(subStr, 16);
            crc = calc_crc(crc, input);
        }
        // 输出String字样的16进制
        String strCrc = Integer.toHexString(crc).toUpperCase();
        return strCrc;
    }

    public static int calc_crc(int crc_buff, int input) {
        int x16 = 0x0000;
        int temp = 0;
        for (int i = 0; i < 8; i++) {
            temp = (crc_buff & 0x0001) ^ (input & 0x01);
            if (temp > 0) {
                x16 = 0x8408;
            } else {
                x16 = 0x0000;
            }
            // shift crc buffer
            crc_buff = crc_buff >> 1;
            // XOR in the x16 value
            crc_buff ^= x16;
            // XOR in the x16 value
            input = input >> 1;
        }
        return crc_buff;
    }

    /**
     *
     * 根据不同设备不同的转换率，对解析的数值进行转换。
     * 例如：channel=01代表储液罐的储液量，该参数的转换率为0.1,，读取的数据为：value=821，则实际的值为：821*0.1=82.1%
     *
     * @param channel 设备
     * @param value
     * @return
     */
    public static String valueChange(String channel, String value){
        String data = value;
        if(channel.equals("01")){
            data = String.valueOf(Integer.parseInt(value)*0.1);
        }else if(channel.equals("02")){
            data = String.valueOf(Integer.parseInt(value)*0.01);
        }
        return data;
    }

    /**
     * 根据类型不同 字节长度也不同 的value转换
     *
     * @param type
     * @param dataHex
     * @return
     */
    public static String calValueByType(String type, String value) {
        // 计算16进制<value>对应的值--start-----------------------
        // 字节转换，如：666696C1->C1966666 --start
        String[] valueArray = new String[value.length() / 2];
        String dataHex = new String();
        String valueStr = new String();
        for (int i = 0; i < valueArray.length; i++) {
            valueArray[i] = value.substring(i * 2, i * 2 + 2);
        }
        for (int i = valueArray.length - 1; i >= 0; i--) {
            dataHex += valueArray[i];
        }
        // 字节转换，如：666696C1->C1966666 --end
        //System.out.println("1.data - Hex =" + dataHex);
        // 根据type（数据类型）对<value>采用数据转换方式
        if (type.equals("10")) {// UChar 无符号 1byte
            int a = Integer.parseInt(dataHex, 16);
            //System.out.println("UChar 无符号  " + dataHex + " = " + a);
            valueStr = String.valueOf(a);
        } else if (type.equals("11")) {// Char 有符号 1byte
            int i = Integer.parseInt(dataHex, 16);
            if ((i - 127) > 0) {
                i = 0 - (255 - i + 1);
            }
            //System.out.println("Char 有符号 " + dataHex + " = " + i);
            valueStr = String.valueOf(i);
        } else if (type.equals("12")) {// UShort 无符号 2byte
            int c = Integer.parseInt(dataHex, 16);
            //System.out.println("UChar 无符号 = " + c);
//			short a = Short.parseShort(dataHex, 16);
            //System.out.println("UShort 无符号 = " + a);
            valueStr = String.valueOf(c);
        } else if (type.equals("13")) {// Short 有符号 2byte
            int a = Integer.parseInt(dataHex, 16);
            if ((a - 65535) > 0) {
                a = 0 - (65535 - a);
            }
            //System.out.println("Short 有符号 " + dataHex + " = " + a);
            valueStr = String.valueOf(a);
        } else if (type.equals("14")) {// ULong 无符号 4byte
            long l = Long.parseLong(dataHex, 16);
            //System.out.println("long 无符号 " + dataHex + " = " + l);
            valueStr = String.valueOf(l);
        } else if (type.equals("15")) {// Long 有符号 4byte
            long l = Long.parseLong(dataHex, 16);
            if ((l - 4294967295L) > 0) {
                l = 0L - (4294967295L - l);
            }
            //System.out.println("long 有符号 " + dataHex + " = " + l);
            valueStr = String.valueOf(l);
        } else if (type.equals("16")) {// Float 有符号 4byte
            // 换位后转为2进制字符串
            String dataBinary = new String();
            dataBinary = hexString2binaryString(dataHex);
            //System.out.println("2.1data -    Binary = " + dataBinary);
            //System.out.println("2.2dataHex - Binary = "
//					+ hexString2binaryString(dataHex));

            String first = dataBinary.substring(0, 1);
            //System.out.println("3.first =" + first);
            // 16进制浮点数转换
            float a = 0;
            if (first.equals("1")) {
                dataHex = binaryString2hexString("0"
                        + dataBinary.substring(1, dataBinary.length()));
                a = a - Float.intBitsToFloat(Integer.parseInt(dataHex, 16));
            } else {
                a = Float.intBitsToFloat(Integer.parseInt(dataHex, 16));
            }
            //System.out.println(a);
            valueStr = String.valueOf(a);

            BigDecimal bd = new BigDecimal(valueStr);

            bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);

            valueStr = bd.toString();
        }

        return valueStr;
        // 计算16进制<value>对应的值--end-----------------------
    }

    /**
     * 16进制字符串转2进制字符串。
     *
     * @param hexString
     * @return
     */
    public static String hexString2binaryString(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0)
            return null;
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000"
                    + Integer.toBinaryString(Integer.parseInt(hexString
                    .substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);
        }
        return bString;
    }

    /**
     * 2进制转16进制
     *
     * @param bString
     * @return
     */
    public static String binaryString2hexString(String bString) {
        if (bString == null || bString.equals("")
                || bString.length() % 8 != 0)
            return null;
        StringBuffer tmp = new StringBuffer();
        int iTmp = 0;
        for (int i = 0; i < bString.length(); i += 4) {
            iTmp = 0;
            for (int j = 0; j < 4; j++) {
                iTmp += Integer.parseInt(bString
                        .substring(i + j, i + j + 1)) << (4 - j - 1);
            }
            tmp.append(Integer.toHexString(iTmp));
        }
        return tmp.toString();
    }
    //字符串转16进制
    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;

        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString().trim();
    }
    /**
     * 16进制转换成为string类型字符串
     * @param s
     * @return
     */
    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "UTF-8");
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }
}
